﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Xml;
using System.Xml.Linq;

namespace Pavilion
{
    public class ResourceManager
    {
        private static ResourceManager instance;

        public IServiceProvider Services { get { return Content.ServiceProvider; } }
        public ContentManager Content { get; private set; }
        public NotifiableCollection<ResourceBase> ResourceCollection { get { return resourceDictionary.ValueCollection; } }

        private NotifiableDictionary<string, ResourceBase> resourceDictionary;
        private AnimationXmlSerializer animationSerializer;
        private ScriptXmlSerializer scriptXmlSerializer;
        private NameChangedDelegate nameChangedDelegate;

        private ResourceManager()
        {
            instance = this;

            resourceDictionary = new NotifiableDictionary<string, ResourceBase>();
            animationSerializer = new AnimationXmlSerializer();
            scriptXmlSerializer = new ScriptXmlSerializer();

            nameChangedDelegate = (oldName, newName) => resourceDictionary.ReplaceKey(oldName, newName);
        }

        public void Initialize(IServiceProvider services)
        {
            this.Content = new ContentManager(services);
        }

        public void UnloadContent()
        {
            Content.Unload();

            foreach (ResourceBase resourceItem in resourceDictionary.ValueCollection)
                resourceItem.Dispose();

            resourceDictionary.Clear();
        }

        public void AddResourceItem(ResourceBase resourceItem)
        {
            resourceDictionary.Add(resourceItem.Name, resourceItem);

            resourceItem.NameChanged += nameChangedDelegate;
        }

        public bool RemoveResource(string resourceName)
        {
            resourceDictionary[resourceName].NameChanged -= nameChangedDelegate;

            return resourceDictionary.Remove(resourceName);
        }

        /// <summary>
        /// Gets the single instance of this class.
        /// </summary>
        static public ResourceManager Instance
        {
            get
            {
                if (instance == null)
                    new ResourceManager();

                return instance;
            }
        }

        public ResourceBase LoadResource(string resourceName)
        {
            if (resourceDictionary.ContainsKey(resourceName))
                return resourceDictionary[resourceName];

            AnimationResource animationResource = new AnimationResource(resourceName);
            AddResourceItem(animationResource);

            animationResource.AddAnimationList(CreateAnimationsFromXmlScript(animationResource.ResourcePath, animationResource.BuiltDataPath));

            animationResource.RootContainer = scriptXmlSerializer.DeserializeScript(GameEngine.AnimationsDirectory + resourceName + @"\Script.xml", resourceName);

            return animationResource;
        }

        private IEnumerable<Animation> CreateAnimationsFromXmlScript(string resourcePath, string builtDataPath)
        {
            IEnumerable<Animation> animationList = animationSerializer.DeserializeCollection(resourcePath + "AnimationList.xml");

            foreach (Animation animation in animationList)
            {
                for (int i = 0; i < animation.FrameList.Count; i++)
                    animation.FrameList[i].CreateTexturesFromFolder(builtDataPath + animation.Name + @"\" + i);
            }

            return animationList;
        }

        public ResourceBase this[string resourceName]
        {
            get
            {
                try { return resourceDictionary[resourceName]; }
                catch { return LoadResource(resourceName); }
            }
        }

        public bool Contains(string resourceName)
        {
            return resourceDictionary.ContainsKey(resourceName);
        }
    }
}
